<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js light">
    <head>
        <!-- Book generated using mdBook -->
        <meta charset="UTF-8">
        <title>过程宏</title>
        
        


        <!-- Custom HTML head -->
        


        <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
        <meta name="description" content="">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <meta name="theme-color" content="#ffffff" />

        
        <link rel="icon" href="favicon.svg">
        
        
        <link rel="shortcut icon" href="favicon.png">
        
        <link rel="stylesheet" href="css/variables.css">
        <link rel="stylesheet" href="css/general.css">
        <link rel="stylesheet" href="css/chrome.css">
        <link rel="stylesheet" href="css/print.css" media="print">

        <!-- Fonts -->
        <link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
        
        <link rel="stylesheet" href="fonts/fonts.css">
        

        <!-- Highlight.js Stylesheets -->
        <link rel="stylesheet" href="highlight.css">
        <link rel="stylesheet" href="tomorrow-night.css">
        <link rel="stylesheet" href="ayu-highlight.css">

        <!-- Custom theme stylesheets -->
        
        <link rel="stylesheet" href="theme/reference.css">
        

        
    </head>
    <body>
        <!-- Provide site root to javascript -->
        <script type="text/javascript">
            var path_to_root = "";
            var default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? "navy" : "light";
        </script>

        <!-- Work around some values being stored in localStorage wrapped in quotes -->
        <script type="text/javascript">
            try {
                var theme = localStorage.getItem('mdbook-theme');
                var sidebar = localStorage.getItem('mdbook-sidebar');

                if (theme.startsWith('"') && theme.endsWith('"')) {
                    localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
                }

                if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
                    localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
                }
            } catch (e) { }
        </script>

        <!-- Set the theme before any content is loaded, prevents flash -->
        <script type="text/javascript">
            var theme;
            try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
            if (theme === null || theme === undefined) { theme = default_theme; }
            var html = document.querySelector('html');
            html.classList.remove('no-js')
            html.classList.remove('light')
            html.classList.add(theme);
            html.classList.add('js');
        </script>

        <!-- Hide / unhide sidebar before it is displayed -->
        <script type="text/javascript">
            var html = document.querySelector('html');
            var sidebar = 'hidden';
            if (document.body.clientWidth >= 1080) {
                try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
                sidebar = sidebar || 'visible';
            }
            html.classList.remove('sidebar-visible');
            html.classList.add("sidebar-" + sidebar);
        </script>

        <nav id="sidebar" class="sidebar" aria-label="Table of contents">
            <div class="sidebar-scrollbox">
                <ol class="chapter"><li class="chapter-item expanded affix "><a href="翻译说明.html">翻译说明</a></li><li class="chapter-item expanded affix "><a href="introduction.html">介绍</a></li><li class="chapter-item expanded "><a href="notation.html"><strong aria-hidden="true">1.</strong> 表义符</a></li><li class="chapter-item expanded "><a href="lexical-structure.html"><strong aria-hidden="true">2.</strong> 词法结构</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="input-format.html"><strong aria-hidden="true">2.1.</strong> 输入格式</a></li><li class="chapter-item expanded "><a href="keywords.html"><strong aria-hidden="true">2.2.</strong> 关键字</a></li><li class="chapter-item expanded "><a href="identifiers.html"><strong aria-hidden="true">2.3.</strong> 标识符</a></li><li class="chapter-item expanded "><a href="comments.html"><strong aria-hidden="true">2.4.</strong> 注释</a></li><li class="chapter-item expanded "><a href="whitespace.html"><strong aria-hidden="true">2.5.</strong> 空白符</a></li><li class="chapter-item expanded "><a href="tokens.html"><strong aria-hidden="true">2.6.</strong> token</a></li><li class="chapter-item expanded "><a href="paths.html"><strong aria-hidden="true">2.7.</strong> 路径</a></li></ol></li><li class="chapter-item expanded "><a href="macros.html"><strong aria-hidden="true">3.</strong> 宏</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="macros-by-example.html"><strong aria-hidden="true">3.1.</strong> 声明宏</a></li><li class="chapter-item expanded "><a href="procedural-macros.html" class="active"><strong aria-hidden="true">3.2.</strong> 过程宏</a></li></ol></li><li class="chapter-item expanded "><a href="crates-and-source-files.html"><strong aria-hidden="true">4.</strong> crate 和源文件</a></li><li class="chapter-item expanded "><a href="conditional-compilation.html"><strong aria-hidden="true">5.</strong> 条件编译</a></li><li class="chapter-item expanded "><a href="items.html"><strong aria-hidden="true">6.</strong> 程序项</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="items/modules.html"><strong aria-hidden="true">6.1.</strong> 模块</a></li><li class="chapter-item expanded "><a href="items/extern-crates.html"><strong aria-hidden="true">6.2.</strong> 外部crate</a></li><li class="chapter-item expanded "><a href="items/use-declarations.html"><strong aria-hidden="true">6.3.</strong> use声明</a></li><li class="chapter-item expanded "><a href="items/functions.html"><strong aria-hidden="true">6.4.</strong> 函数</a></li><li class="chapter-item expanded "><a href="items/type-aliases.html"><strong aria-hidden="true">6.5.</strong> 类型别名</a></li><li class="chapter-item expanded "><a href="items/structs.html"><strong aria-hidden="true">6.6.</strong> 结构体</a></li><li class="chapter-item expanded "><a href="items/enumerations.html"><strong aria-hidden="true">6.7.</strong> 枚举</a></li><li class="chapter-item expanded "><a href="items/unions.html"><strong aria-hidden="true">6.8.</strong> 联合体</a></li><li class="chapter-item expanded "><a href="items/constant-items.html"><strong aria-hidden="true">6.9.</strong> 常量项</a></li><li class="chapter-item expanded "><a href="items/static-items.html"><strong aria-hidden="true">6.10.</strong> 静态项</a></li><li class="chapter-item expanded "><a href="items/traits.html"><strong aria-hidden="true">6.11.</strong> trait</a></li><li class="chapter-item expanded "><a href="items/implementations.html"><strong aria-hidden="true">6.12.</strong> 实现</a></li><li class="chapter-item expanded "><a href="items/external-blocks.html"><strong aria-hidden="true">6.13.</strong> 外部块</a></li><li class="chapter-item expanded "><a href="items/generics.html"><strong aria-hidden="true">6.14.</strong> 类型参数和生存期参数</a></li><li class="chapter-item expanded "><a href="items/associated-items.html"><strong aria-hidden="true">6.15.</strong> 关联程序项</a></li><li class="chapter-item expanded "><a href="visibility-and-privacy.html"><strong aria-hidden="true">6.16.</strong> 可见性与隐私权</a></li></ol></li><li class="chapter-item expanded "><a href="attributes.html"><strong aria-hidden="true">7.</strong> 属性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="attributes/testing.html"><strong aria-hidden="true">7.1.</strong> 测试</a></li><li class="chapter-item expanded "><a href="attributes/derive.html"><strong aria-hidden="true">7.2.</strong> 派生</a></li><li class="chapter-item expanded "><a href="attributes/diagnostics.html"><strong aria-hidden="true">7.3.</strong> 诊断</a></li><li class="chapter-item expanded "><a href="attributes/codegen.html"><strong aria-hidden="true">7.4.</strong> 代码生成</a></li><li class="chapter-item expanded "><a href="attributes/limits.html"><strong aria-hidden="true">7.5.</strong> 极限设置</a></li><li class="chapter-item expanded "><a href="attributes/type_system.html"><strong aria-hidden="true">7.6.</strong> 类型系统</a></li></ol></li><li class="chapter-item expanded "><a href="statements-and-expressions.html"><strong aria-hidden="true">8.</strong> 语句和表达式</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="statements.html"><strong aria-hidden="true">8.1.</strong> 语句</a></li><li class="chapter-item expanded "><a href="expressions.html"><strong aria-hidden="true">8.2.</strong> 表达式</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="expressions/literal-expr.html"><strong aria-hidden="true">8.2.1.</strong> 字面量表达式</a></li><li class="chapter-item expanded "><a href="expressions/path-expr.html"><strong aria-hidden="true">8.2.2.</strong> 路径表达式</a></li><li class="chapter-item expanded "><a href="expressions/block-expr.html"><strong aria-hidden="true">8.2.3.</strong> 块表达式</a></li><li class="chapter-item expanded "><a href="expressions/operator-expr.html"><strong aria-hidden="true">8.2.4.</strong> 运算符表达式</a></li><li class="chapter-item expanded "><a href="expressions/grouped-expr.html"><strong aria-hidden="true">8.2.5.</strong> 分组表达式</a></li><li class="chapter-item expanded "><a href="expressions/array-expr.html"><strong aria-hidden="true">8.2.6.</strong> 数组和索引表达式</a></li><li class="chapter-item expanded "><a href="expressions/tuple-expr.html"><strong aria-hidden="true">8.2.7.</strong> 元组和索引表达式</a></li><li class="chapter-item expanded "><a href="expressions/struct-expr.html"><strong aria-hidden="true">8.2.8.</strong> 结构体表达式</a></li><li class="chapter-item expanded "><a href="expressions/enum-variant-expr.html"><strong aria-hidden="true">8.2.9.</strong> 枚举变体表达式</a></li><li class="chapter-item expanded "><a href="expressions/call-expr.html"><strong aria-hidden="true">8.2.10.</strong> 调用表达式</a></li><li class="chapter-item expanded "><a href="expressions/method-call-expr.html"><strong aria-hidden="true">8.2.11.</strong> 方法调用表达式</a></li><li class="chapter-item expanded "><a href="expressions/field-expr.html"><strong aria-hidden="true">8.2.12.</strong> 字段访问表达式</a></li><li class="chapter-item expanded "><a href="expressions/closure-expr.html"><strong aria-hidden="true">8.2.13.</strong> 闭包表达式</a></li><li class="chapter-item expanded "><a href="expressions/loop-expr.html"><strong aria-hidden="true">8.2.14.</strong> 循环表达式</a></li><li class="chapter-item expanded "><a href="expressions/range-expr.html"><strong aria-hidden="true">8.2.15.</strong> 区间表达式</a></li><li class="chapter-item expanded "><a href="expressions/if-expr.html"><strong aria-hidden="true">8.2.16.</strong> if 和 if let 表达式</a></li><li class="chapter-item expanded "><a href="expressions/match-expr.html"><strong aria-hidden="true">8.2.17.</strong> 匹配表达式</a></li><li class="chapter-item expanded "><a href="expressions/return-expr.html"><strong aria-hidden="true">8.2.18.</strong> 返回表达式</a></li><li class="chapter-item expanded "><a href="expressions/await-expr.html"><strong aria-hidden="true">8.2.19.</strong> 等待(await)表达式</a></li></ol></li></ol></li><li class="chapter-item expanded "><a href="patterns.html"><strong aria-hidden="true">9.</strong> 模式</a></li><li class="chapter-item expanded "><a href="type-system.html"><strong aria-hidden="true">10.</strong> 类型系统</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="types.html"><strong aria-hidden="true">10.1.</strong> 类型</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="types/boolean.html"><strong aria-hidden="true">10.1.1.</strong> 布尔型</a></li><li class="chapter-item expanded "><a href="types/numeric.html"><strong aria-hidden="true">10.1.2.</strong> 数字型</a></li><li class="chapter-item expanded "><a href="types/textual.html"><strong aria-hidden="true">10.1.3.</strong> 字符型</a></li><li class="chapter-item expanded "><a href="types/never.html"><strong aria-hidden="true">10.1.4.</strong> never类型</a></li><li class="chapter-item expanded "><a href="types/tuple.html"><strong aria-hidden="true">10.1.5.</strong> 元组</a></li><li class="chapter-item expanded "><a href="types/array.html"><strong aria-hidden="true">10.1.6.</strong> 数组</a></li><li class="chapter-item expanded "><a href="types/slice.html"><strong aria-hidden="true">10.1.7.</strong> 切片</a></li><li class="chapter-item expanded "><a href="types/struct.html"><strong aria-hidden="true">10.1.8.</strong> 结构体</a></li><li class="chapter-item expanded "><a href="types/enum.html"><strong aria-hidden="true">10.1.9.</strong> 枚举</a></li><li class="chapter-item expanded "><a href="types/union.html"><strong aria-hidden="true">10.1.10.</strong> 联合体</a></li><li class="chapter-item expanded "><a href="types/function-item.html"><strong aria-hidden="true">10.1.11.</strong> 函数项类型</a></li><li class="chapter-item expanded "><a href="types/closure.html"><strong aria-hidden="true">10.1.12.</strong> 闭包</a></li><li class="chapter-item expanded "><a href="types/pointer.html"><strong aria-hidden="true">10.1.13.</strong> 指针型</a></li><li class="chapter-item expanded "><a href="types/function-pointer.html"><strong aria-hidden="true">10.1.14.</strong> 函数指针</a></li><li class="chapter-item expanded "><a href="types/trait-object.html"><strong aria-hidden="true">10.1.15.</strong> trait对象</a></li><li class="chapter-item expanded "><a href="types/impl-trait.html"><strong aria-hidden="true">10.1.16.</strong> 实现trait</a></li><li class="chapter-item expanded "><a href="types/parameters.html"><strong aria-hidden="true">10.1.17.</strong> 类型参数</a></li><li class="chapter-item expanded "><a href="types/inferred.html"><strong aria-hidden="true">10.1.18.</strong> 推断型</a></li></ol></li><li class="chapter-item expanded "><a href="dynamically-sized-types.html"><strong aria-hidden="true">10.2.</strong> 动态尺寸类型(DST)</a></li><li class="chapter-item expanded "><a href="type-layout.html"><strong aria-hidden="true">10.3.</strong> 类型布局 </a></li><li class="chapter-item expanded "><a href="interior-mutability.html"><strong aria-hidden="true">10.4.</strong> 内部可变性</a></li><li class="chapter-item expanded "><a href="subtyping.html"><strong aria-hidden="true">10.5.</strong> 子类型和型变</a></li><li class="chapter-item expanded "><a href="trait-bounds.html"><strong aria-hidden="true">10.6.</strong> trait约束及其生存期约束</a></li><li class="chapter-item expanded "><a href="type-coercions.html"><strong aria-hidden="true">10.7.</strong> 类型自动强转</a></li><li class="chapter-item expanded "><a href="destructors.html"><strong aria-hidden="true">10.8.</strong> 析构函数</a></li><li class="chapter-item expanded "><a href="lifetime-elision.html"><strong aria-hidden="true">10.9.</strong> 生存期省略</a></li></ol></li><li class="chapter-item expanded "><a href="special-types-and-traits.html"><strong aria-hidden="true">11.</strong> 特殊类型和 trait</a></li><li class="chapter-item expanded "><a href="memory-model.html"><strong aria-hidden="true">12.</strong> 内存模型</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="memory-allocation-and-lifetime.html"><strong aria-hidden="true">12.1.</strong> 内存分配和其生存期</a></li><li class="chapter-item expanded "><a href="memory-ownership.html"><strong aria-hidden="true">12.2.</strong> 内存所有权</a></li><li class="chapter-item expanded "><a href="variables.html"><strong aria-hidden="true">12.3.</strong> 变量</a></li></ol></li><li class="chapter-item expanded "><a href="linkage.html"><strong aria-hidden="true">13.</strong> 链接(linkage)</a></li><li class="chapter-item expanded "><a href="unsafety.html"><strong aria-hidden="true">14.</strong> 非安全性</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="unsafe-functions.html"><strong aria-hidden="true">14.1.</strong> 非安全函数</a></li><li class="chapter-item expanded "><a href="unsafe-blocks.html"><strong aria-hidden="true">14.2.</strong> 非安全代码块</a></li><li class="chapter-item expanded "><a href="behavior-considered-undefined.html"><strong aria-hidden="true">14.3.</strong> 未定义行为</a></li><li class="chapter-item expanded "><a href="behavior-not-considered-unsafe.html"><strong aria-hidden="true">14.4.</strong> 不被认为是非安全的行为</a></li></ol></li><li class="chapter-item expanded "><a href="const_eval.html"><strong aria-hidden="true">15.</strong> 常量求值</a></li><li class="chapter-item expanded "><a href="abi.html"><strong aria-hidden="true">16.</strong> ABI</a></li><li class="chapter-item expanded "><a href="runtime.html"><strong aria-hidden="true">17.</strong> Rust运行时</a></li><li class="chapter-item expanded "><a href="appendices.html"><strong aria-hidden="true">18.</strong> 附录</a></li><li><ol class="section"><li class="chapter-item expanded "><a href="macro-ambiguity.html"><strong aria-hidden="true">18.1.</strong> 宏定义规范</a></li><li class="chapter-item expanded "><a href="influences.html"><strong aria-hidden="true">18.2.</strong> 影响来源</a></li><li class="chapter-item expanded "><a href="glossary.html"><strong aria-hidden="true">18.3.</strong> 术语表</a></li><li class="chapter-item expanded "><a href="本书术语翻译对照表.html"><strong aria-hidden="true">18.4.</strong> 本书术语翻译对照表</a></li></ol></li></ol>
            </div>
            <div id="sidebar-resize-handle" class="sidebar-resize-handle"></div>
        </nav>

        <div id="page-wrapper" class="page-wrapper">

            <div class="page">
                
                <div id="menu-bar-hover-placeholder"></div>
                <div id="menu-bar" class="menu-bar sticky bordered">
                    <div class="left-buttons">
                        <button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
                            <i class="fa fa-bars"></i>
                        </button>
                        <button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
                            <i class="fa fa-paint-brush"></i>
                        </button>
                        <ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
                            <li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
                            <li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
                        </ul>
                        
                        <button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
                            <i class="fa fa-search"></i>
                        </button>
                        
                    </div>

                    <h1 class="menu-title"></h1>

                    <div class="right-buttons">
                        <a href="print.html" title="Print this book" aria-label="Print this book">
                            <i id="print-button" class="fa fa-print"></i>
                        </a>
                        
                        <a href="https://gitee.com/minstrel1977/rust-reference" title="Git repository" aria-label="Git repository">
                            <i id="git-repository-button" class="fa fa-github"></i>
                        </a>
                        
                    </div>
                </div>

                
                <div id="search-wrapper" class="hidden">
                    <form id="searchbar-outer" class="searchbar-outer">
                        <input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
                    </form>
                    <div id="searchresults-outer" class="searchresults-outer hidden">
                        <div id="searchresults-header" class="searchresults-header"></div>
                        <ul id="searchresults">
                        </ul>
                    </div>
                </div>
                

                <!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
                <script type="text/javascript">
                    document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
                    document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
                    Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
                        link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
                    });
                </script>

                <div id="content" class="content">
                    <main>
                        <h2><a class="header" href="#procedural-macros" id="procedural-macros">Procedural Macros</a></h2>
<h2><a class="header" href="#过程宏" id="过程宏">过程宏</a></h2>
<blockquote>
<p><a href="https://github.com/rust-lang/reference/blob/master/src/procedural-macros.md">procedural-macros.md</a><br />
commit: a1ef5a09c0281b0f2a65c18670e927ead61eb1b2 <br />
本章译文最后维护日期：2020-11-6</p>
</blockquote>
<p><em>过程宏</em>允许在执行函数时创建句法扩展。过程宏有三种形式:</p>
<ul>
<li><a href="#function-like-procedural-macros">类函数宏(function-like macros)</a> - <code>custom!(...)</code></li>
<li><a href="#derive-macros">派生宏(derive macros)</a>- <code>#[derive(CustomDerive)]</code></li>
<li><a href="#attribute-macros">属性宏(attribute macros)</a> - <code>#[CustomAttribute]</code></li>
</ul>
<p>过程宏允许在编译时运行对 Rust 句法进行操作的代码，它可以在消费掉一些 Rust 句法输入的同时产生新的 Rust 句法输出。可以将过程宏想象成是从一个 <abbr title="抽象句法树：Abstract Syntax Tree">AST</abbr> 到另一个 <abbr title="抽象句法树：Abstract Syntax Tree">AST</abbr> 的函数映射。</p>
<p>过程宏必须在 <a href="linkage.html">crate 类型</a>为 <code>proc-macro</code> 的 crate 中定义。</p>
<blockquote>
<p><strong>注意</strong>: 使用 Cargo 时，定义过程宏的 crate 的配置文件里要使用 <code>proc-macro</code>键做如下设置：</p>
<pre><code class="language-toml">[lib]
proc-macro = true
</code></pre>
</blockquote>
<p>作为函数，它们要么有返回句法，要么触发 panic，要么永无休止地循环。返回句法根据过程宏的类型替换或添加句法；panic 会被编译器捕获，并将其转化为编译器错误；无限循环不会被编译器不会捕获，但会导致编译器被挂起。</p>
<p>过程宏在编译时运行，因此具有与编译器相同的环境资源。例如，它可以访问的标准输入、标准输出和标准错误输出等，这些编译器可以访问的资源。类似地，文件访问也是一样的。因此，过程宏与 <a href="https://doc.rust-lang.org/cargo/reference/build-scripts.html">Cargo构建脚本</a> 具有相同的安全考量。</p>
<p>过程宏有两种报告错误的方法。首先是 panic；第二个是发布 <a href="https://doc.rust-lang.org/std/macro.compile_error.html"><code>compile_error</code></a> 性质的宏调用。</p>
<h3><a class="header" href="#the-proc_macro-crate" id="the-proc_macro-crate">The <code>proc_macro</code> crate</a></h3>
<p>过程宏类型的 crate 几乎总是会去链接编译器提供的 <a href="https://doc.rust-lang.org/proc_macro/index.html"><code>proc_macro</code> crate</a>。<code>proc_macro</code> crate 提供了编写过程宏所需的各种类型和工具来让编写更容易。</p>
<p>此 crate 主要包含了一个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 类型。过程宏其实是在 *token流(token streams)*上操作，而不是在某个或某些 AST 节点上操作，因为这对于编译器和过程宏的编译目标来说，这是一个随着时间推移要稳定得多的接口。<em>token流</em>大致相当于 <code>Vec&lt;TokenTree&gt;</code>，其中 <code>TokenTree</code> 可以大致视为词法 token。例如，<code>foo</code> 是标识符(<code>Ident</code>)类型的 token，<code>.</code> 是一个标点符号(<code>Punct</code>)类型的 token，<code>1.2</code> 是一个字面量(<code>Literal</code>)类型的 token。不同于 <code>Vec&lt;TokenTree&gt;</code> 的是 <code>TokenStream</code> 的克隆成本很低。</p>
<p>所有类型的 token 都有一个与之关联的 <code>Span</code>。<code>Span</code> 是一个不透明的值，不能被修改，但可以被制造。<code>Span</code> 表示程序内的源代码范围，主要用于错误报告。可以事先（通过函数 <code>set_span</code>）配置任何 token 的 <code>Span</code>。</p>
<h3><a class="header" href="#procedural-macro-hygiene" id="procedural-macro-hygiene">Procedural macro hygiene</a></h3>
<h3><a class="header" href="#过程宏的卫生性" id="过程宏的卫生性">过程宏的卫生性</a></h3>
<p>过程宏是<em>非卫生的(unhygienic)</em>。这意味着它的行为就好像它输出的 token流是被简单地内联写入它周围的代码中一样。这意味着它会受到外部程序项的影响，也会影响外部导入。</p>
<p>鉴于此限制，宏作者需要小心地确保他们的宏能在尽可能多的上下文中正常工作。这通常包括对库中程序项使用绝对路径(例如，使用 <code>::std::option::Option</code> 而不是 <code>Option</code>)，或者确保生成的函数具有不太可能与其他函数冲突的名称（如 <code>__internal_foo</code>，而不是 <code>foo</code>）。</p>
<h3><a class="header" href="#function-like-procedural-macros" id="function-like-procedural-macros">Function-like procedural macros</a></h3>
<h3><a class="header" href="#类函数过程宏" id="类函数过程宏">类函数过程宏</a></h3>
<p><em>类函数过程宏</em>是使用宏调用运算符（<code>!</code>）调用的过程宏。</p>
<p>这种宏是由一个带有 <code>proc_macro</code><a href="attributes.html">属性</a>和 <code>(TokenStream) -&gt; TokenStream</code>签名的 <a href="visibility-and-privacy.html">公有</a>可见性<a href="items/functions.html">函数</a>定义。输入 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是由宏调用的定界符界定的内容，输出 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 将替换整个宏调用。</p>
<p>例如，下面的宏定义忽略它的输入，并将函数 <code>answer</code> 输出到它的作用域。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type = &quot;proc-macro&quot;]
</span>extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro]
pub fn make_answer(_item: TokenStream) -&gt; TokenStream {
    &quot;fn answer() -&gt; u32 { 42 }&quot;.parse().unwrap()
}
</code></pre>
<p>然后我们用它在一个二进制 crate 里打印 “42” 到标准输出。</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">extern crate proc_macro_examples;
use proc_macro_examples::make_answer;

make_answer!();

fn main() {
    println!(&quot;{}&quot;, answer());
}
</code></pre>
<p>类函数过程宏可以在任何宏调用位置调用，这些位置包括<a href="statements.html">语句</a>、<a href="expressions.html">表达式</a>、<a href="patterns.html">模式</a>、<a href="types.html#type-expressions">类型表达式</a>、<a href="items.html">程序项</a>可以出现的位置（包括<a href="items/external-blocks.html"><code>extern</code>块</a>里、固有(inherent)<a href="items/implementations.html">实现</a>里和 trait实现里、以及 <a href="items/traits.html">trait声明</a>里）。</p>
<h3><a class="header" href="#derive-macros" id="derive-macros">Derive macros</a></h3>
<h3><a class="header" href="#派生宏" id="派生宏">派生宏</a></h3>
<p><em>派生宏</em>为<a href="attributes/derive.html">派生(<code>derive</code>)属性</a>定义新输入。这类宏在给定输入<a href="items/structs.html">结构体(<code>struct</code>)</a>、<a href="items/enumerations.html">枚举(<code>enum</code>)</a>或<a href="items/unions.html">联合体(<code>union</code>)</a> token流的情况下创建新<a href="items.html">程序项</a>。它们也可以定义<a href="#derive-macro-helper-attributes">派生宏辅助属性</a>。</p>
<p>自定义派生宏由带有 <code>proc_macro_derive</code>属性和 <code>(TokenStream) -&gt; TokenStream</code>签名的<a href="visibility-and-privacy.html">公有</a>可见性<a href="items/functions.html">函数</a>定义。</p>
<p>输入 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是带有 <code>derive</code> 属性的程序项的 token流。输出 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 必须是一组程序项，然后将这组程序项追加到输入 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 中的那条程序项所在的<a href="items/modules.html">模块</a>或<a href="expressions/block-expr.html">块</a>中。</p>
<p>下面是派生宏的一个示例。它没有对输入执行任何有用的操作，只是追加了一个函数 <code>answer</code>。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type = &quot;proc-macro&quot;]
</span>extern crate proc_macro;
use proc_macro::TokenStream;

#[proc_macro_derive(AnswerFn)]
pub fn derive_answer_fn(_item: TokenStream) -&gt; TokenStream {
    &quot;fn answer() -&gt; u32 { 42 }&quot;.parse().unwrap()
}
</code></pre>
<p>然后使用这个派生宏：</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">extern crate proc_macro_examples;
use proc_macro_examples::AnswerFn;

#[derive(AnswerFn)]
struct Struct;

fn main() {
    assert_eq!(42, answer());
}
</code></pre>
<h4><a class="header" href="#derive-macro-helper-attributes" id="derive-macro-helper-attributes">Derive macro helper attributes</a></h4>
<h4><a class="header" href="#派生宏辅助属性" id="派生宏辅助属性">派生宏辅助属性</a></h4>
<p>派生宏可以将额外的<a href="attributes.html">属性</a>添加到它们所在的<a href="items.html">程序项</a>的作用域中。这些属性被称为<em>派生宏辅助属性</em>。这些属性是<a href="attributes.html#active-and-inert-attributes">惰性的</a>，它们存在的唯一目的是将这些属性在使用现场获得的属性值反向输入到定义它们的派生宏中。也就是说所有该宏的宏应用都可以看到它们。</p>
<p>定义辅助属性的方法是在 <code>proc_macro_derive</code> 宏中放置一个 <code>attributes</code> 键，此键带有一个使用逗号分隔的标识符列表，这些标识符是辅助属性的名称。</p>
<p>例如，下面的派生宏定义了一个辅助属性 <code>helper</code>，但最终没有用它做任何事情。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type=&quot;proc-macro&quot;]
</span><span class="boring">extern crate proc_macro;
</span><span class="boring">use proc_macro::TokenStream;
</span>
#[proc_macro_derive(HelperAttr, attributes(helper))]
pub fn derive_helper_attr(_item: TokenStream) -&gt; TokenStream {
    TokenStream::new()
}
</code></pre>
<p>然后在一个结构体上使用这个派生宏：</p>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">#[derive(HelperAttr)]
struct Struct {
    #[helper] field: ()
}
</code></pre>
<h3><a class="header" href="#attribute-macros" id="attribute-macros">Attribute macros</a></h3>
<h3><a class="header" href="#属性宏" id="属性宏">属性宏</a></h3>
<p><em>属性宏</em>定义可以附加到<a href="items.html">程序项</a>上的新的<a href="attributes.html">外部属性</a>，这些程序项包括<a href="items/external-blocks.html">外部(<code>extern</code>)块</a>、固有<a href="items/implementations.html">实现</a>、trate实现，以及 <a href="items/traits.html">trait声明</a>中的各类程序项。</p>
<p>属性宏由带有 <code>proc_macro_attribute</code><a href="attributes.html">属性</a>和 <code>(TokenStream, TokenStream) -&gt; TokenStream</code>签名的<a href="visibility-and-privacy.html">公有</a>可见性<a href="items/functions.html">函数</a>定义。签名中的第一个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是属性名称后面的定界 token树(delimited token tree)（不包括外层定界符）。如果该属性作为裸属性(bare attribute)给出，则第一个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 值为空。第二个 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 是<a href="items.html">程序项</a>的其余部分，包括该程序项的其他<a href="attributes.html">属性</a>。输出的 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a> 将此属性宏应用的<a href="items.html">程序项</a>替换为任意数量的程序项。</p>
<p>例如，下面这个属性宏接受输入流并按原样返回，实际上对属性并无操作。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore"><span class="boring">#![crate_type = &quot;proc-macro&quot;]
</span><span class="boring">extern crate proc_macro;
</span><span class="boring">use proc_macro::TokenStream;
</span>
#[proc_macro_attribute]
pub fn return_as_is(_attr: TokenStream, item: TokenStream) -&gt; TokenStream {
    item
}
</code></pre>
<p>下面示例显示了属性宏看到的字符串化的 <a href="https://doc.rust-lang.org/proc_macro/struct.TokenStream.html"><code>TokenStream</code></a>。输出将显示在编译时的编译器输出窗口中。（具体格式是以 &quot;out:&quot;为前缀的）输出内容也都在后面每个示例函数后面的注释中给出了。</p>
<!-- ignore: test doesn't support proc-macro -->
<pre><code class="language-rust ignore">// my-macro/src/lib.rs
<span class="boring">extern crate proc_macro;
</span><span class="boring">use proc_macro::TokenStream;
</span>
#[proc_macro_attribute]
pub fn show_streams(attr: TokenStream, item: TokenStream) -&gt; TokenStream {
    println!(&quot;attr: \&quot;{}\&quot;&quot;, attr.to_string());
    println!(&quot;item: \&quot;{}\&quot;&quot;, item.to_string());
    item
}
</code></pre>
<!-- ignore: requires external crates -->
<pre><code class="language-rust ignore">// src/lib.rs
extern crate my_macro;

use my_macro::show_streams;

// 示例: 基础函数
#[show_streams]
fn invoke1() {}
// out: attr: &quot;&quot;
// out: item: &quot;fn invoke1() { }&quot;

// 示例: 带输入参数的属性
#[show_streams(bar)]
fn invoke2() {}
// out: attr: &quot;bar&quot;
// out: item: &quot;fn invoke2() {}&quot;

// 示例: 输入参数中有多个 token 的
#[show_streams(multiple =&gt; tokens)]
fn invoke3() {}
// out: attr: &quot;multiple =&gt; tokens&quot;
// out: item: &quot;fn invoke3() {}&quot;

// 示例:
#[show_streams { delimiters }]
fn invoke4() {}
// out: attr: &quot;delimiters&quot;
// out: item: &quot;fn invoke4() {}&quot;
</code></pre>
<!-- 2020-11-12-->
<!-- checked -->
                    </main>

                    <nav class="nav-wrapper" aria-label="Page navigation">
                        <!-- Mobile navigation buttons -->
                        
                            <a rel="prev" href="macros-by-example.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                                <i class="fa fa-angle-left"></i>
                            </a>
                        

                        
                            <a rel="next" href="crates-and-source-files.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                                <i class="fa fa-angle-right"></i>
                            </a>
                        

                        <div style="clear: both"></div>
                    </nav>
                </div>
            </div>

            <nav class="nav-wide-wrapper" aria-label="Page navigation">
                
                    <a rel="prev" href="macros-by-example.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
                        <i class="fa fa-angle-left"></i>
                    </a>
                

                
                    <a rel="next" href="crates-and-source-files.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
                        <i class="fa fa-angle-right"></i>
                    </a>
                
            </nav>

        </div>

        

        

        

        
        <script type="text/javascript">
            window.playground_copyable = true;
        </script>
        

        

        
        <script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="searcher.js" type="text/javascript" charset="utf-8"></script>
        

        <script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
        <script src="highlight.js" type="text/javascript" charset="utf-8"></script>
        <script src="book.js" type="text/javascript" charset="utf-8"></script>

        <!-- Custom JS scripts -->
        

        

    </body>
</html>
